package com.neighbor.spring.mysql.rowmapper;


import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;

import javax.persistence.Column;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.*;


/**
 * @author ysw
 * @create 2019-04-22 15:08
 * @descreption
 **/
public class AnnotationSqlParameterSource implements SqlParameterSource {


    private  Map<String, String> propWithColumn;
    private final BeanWrapper beanWrapper;
    private String[] propertyNames;

    public AnnotationSqlParameterSource(Object obj) {
        this.beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
        propWithColumn = getPropertyWithColumn(obj.getClass());
    }

    public String[] getReadablePropertyNames() {
        if (this.propertyNames == null) {
            List<String> names = new ArrayList<>();
            PropertyDescriptor[] props = this.beanWrapper.getPropertyDescriptors();
            for (PropertyDescriptor pd : props) {
                if (this.beanWrapper.isReadableProperty(pd.getName())) {
                    names.add(pd.getName());
                }
            }
            this.propertyNames = names.toArray(new String[names.size()]);
        }
        return this.propertyNames;
    }


    public Map<String, String> getPropertyWithColumn(Class clazz) {
        //属性、@数据库列
        Map<String, String> propertyColumn = new HashMap<>();
        List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
        while (clazz != null) {
            clazz = clazz.getSuperclass();
            if (clazz.getName().equals("java.lang.Object")) {
                break;
            }
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
        }
        for (Field field : fields) {
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                propertyColumn.put(field.getName(), column.name());
            } else {
                propertyColumn.put(field.getName(), field.getName());
            }
        }
        return propertyColumn;
    }


    @Override
    public boolean hasValue(String paramName) {
        return this.beanWrapper.isReadableProperty(paramName);
    }

    @Override
    public Object getValue(String paramName) throws IllegalArgumentException {
        return this.beanWrapper.getPropertyValue(paramName);
    }

    @Override
    public int getSqlType(String paramName) {
        Class<?> propType = this.beanWrapper.getPropertyType(paramName);
        return StatementCreatorUtils.javaTypeToSqlParameterType(propType);
    }

    @Override
    public String getTypeName(String paramName) {
        return null;
    }
}
